package com.broad.commerce.code.services.base;

import com.broad.commerce.code.modules.jdbc.EntityModule;
import com.broad.commerce.common.utils.core.AopSpringUtils;
import com.broad.commerce.common.utils.core.StringUtils;
import com.broad.commerce.jdbc.utils.JavaTypeUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author stephen
 * @version V1.0
 * @date 2022-04-28 16:56
 * @description: DataBaseTableService
 **/
@Service
public class DataBaseTableService {
	@PersistenceContext
	private EntityManager entityManager;

	public String createTableDDL(EntityModule entityModule) {
		JavaTypeUtils.initTypes();
		StringBuilder sql = new StringBuilder("CREATE TABLE ").append(entityModule.getTableName().toUpperCase()).append(" (").append("\n");
		sql.append("\t").append("ID BIGINT AUTO_INCREMENT COMMENT '主键ID' PRIMARY KEY,").append("\n");
		entityModule.getEntityFields().forEach(entityField -> {
			sql.append("\t").append(StringUtils.humpToLine(entityField.getFieldName()).toUpperCase());
			Class<?> fieldType = entityField.getFieldType();
			String fieldTypeName = fieldType.getName();
			sql.append("\t").append(JavaTypeUtils.JAVA_TO_JDBC.get(fieldTypeName));
			if (entityField.getLength() > 0) {
				if (fieldType == BigDecimal.class) {
					sql.append("(").append(entityField.getLength()).append(", 2)");
				} else {
					sql.append("(").append(entityField.getLength()).append(")");
				}
			} else {
				if (fieldType == BigDecimal.class) {
					sql.append("(20, 2)");
				} else if (fieldType == String.class) {
					sql.append("(255)");
				}
			}
			if (entityField.getRequired()) {
				sql.append("\t").append("NOT NULL");
				Object defaultValue = entityField.getDefaultValue();
				if (fieldType == Date.class) {
					defaultValue = "CURRENT_TIMESTAMP";
				}
				if (Objects.nonNull(defaultValue)) {
					if (fieldType == String.class || fieldType == Character.class) {
						defaultValue = "'" + defaultValue + "'";
					}
					sql.append("\t").append("DEFAULT ").append(defaultValue);
				}
			}
			sql.append("\t").append("COMMENT '").append(entityField.getFieldComment()).append("',").append("\n");
		});
		sql.deleteCharAt(sql.lastIndexOf(",")).append(")").append("\n");
		sql.append("ENGINE=InnoDB DEFAULT CHARSET=UTF8 COMMENT='").append(entityModule.getComment()).append("';");
		return sql.toString();
	}

	@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
	public void createTable(String sql) {
		this.excuteSQL(sql);
	}

	@Transactional(readOnly = false, propagation = Propagation.REQUIRED)
	public void dropTable(String tableName) {
		String sql = "DROP TABLE IF EXISTS " + tableName.toUpperCase() + ";";
		this.excuteSQL(sql);
	}

	@Transactional(rollbackFor = Exception.class)
	public void excuteSQL(String sql) {
		entityManager.createNativeQuery(sql).executeUpdate();
	}

	@SuppressWarnings("unchecked")
	public List<String> searchAllTableNames() {
		String sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'manage';";
		Query query = entityManager.createNativeQuery(sql);
		return this.getQuery(query).getResultList();
	}

	private Query getQuery(Query query) {
		try {
			return (Query) AopSpringUtils.getTarget(query);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return query;
	}
}

